package br.com.cpqd.ssar.gerenciador;

import br.com.cpqd.ssar.posprocessamento.Visualizador;
import br.com.cpqd.ssar.posprocessamento.gui.JanelaInserirRelatorios;
import br.com.cpqd.ssar.utilitarias.FonteEletromagneticaSimulacao;
import br.com.cpqd.ssar.utilitarias.ListaGeometrias;
import br.com.cpqd.ssar.utilitarias.Geometria;
import br.com.cpqd.ssar.utilitarias.RelatorioPosProcessamento;
import java.util.Vector;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;

/**
 *
 * @author igorj
 */
public class GerenciamentoArvore extends JScrollPane {

    private JTree tree;
    private DefaultMutableTreeNode root = new DefaultMutableTreeNode("Gerenciador");
    /* Declaracao da raiz da arvore de objetos do tipo 'Geometry' */
    private DefaultMutableTreeNode objGeometrias = new DefaultMutableTreeNode("Geometrias");
    /* Declaracao da raiz da arvore de objetos do tipo 'Report' */
    private DefaultMutableTreeNode objRelatorios = new DefaultMutableTreeNode("Relatórios");
    private DefaultMutableTreeNode objFontes = new DefaultMutableTreeNode("Fontes");
    private DefaultTreeModel model;
    private static final int DEFAULT_WIDTH = 300;
    private static final int DEFAULT_HEIGHT = 200;
    DefaultTreeCellRenderer cellRender = new DefaultTreeCellRenderer();
    private Icon iconGeometria = new ImageIcon("/br/com/cpqd/ssar/gerenciador/gui/recursos/addGeometria.gif");
    private Icon iconFonte = new ImageIcon("/br/com/cpqd/ssar/gerenciador/gui/recursos/addGeometria.gif");
    private Icon iconListaGeometria = new ImageIcon("/br/com/cpqd/ssar/gerenciador/gui/recursos/addGeometria.gif");

    public GerenciamentoArvore() {


        cellRender.setOpenIcon(iconGeometria);
        cellRender.setClosedIcon(iconGeometria);
        cellRender.setLeafIcon(iconGeometria);
        /* Arrumar ícones para Geometrias / Lista de Geometrias na árvore */
//        tree.setCellRenderer(cellRender);


        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        root.add(objRelatorios);
        root.add(objGeometrias);
        root.add(objFontes);
        TreeNode root2 = root;
        model = new DefaultTreeModel(root2);
        tree = new JTree(model);
        tree.setEditable(false);
        tree.putClientProperty("JTree.lineStyle", "None");
        tree.setShowsRootHandles(true);


    }

    /**
     * Retorna toda estrutura da árvore, que contém a objGeometrias e objRelatorios
     * @return JTree
     */
    public JTree getTree() {
        return tree;
    }

    /**
     * Retorna Objeto "objGeometrias" que contém a lista de Geometrias
     * @return DefaultMutableTreeNode
     */
    public DefaultMutableTreeNode getObjTree() {
        return objGeometrias;
    }

    /**
     * Retorna Vector com lista de ListaGeometrias 
     * @return Vector ListaGeometrias
     */
    public Vector getListaGeometrias() {
        Vector listVectorGeometry = new Vector();
        /* for para o objeto 'nodeTree' que contem os grupos de objetos
         * e cada grupo de objeto contem uma lista de objetos do tipo Geometry
         */
        Geometria g1 = new Geometria();
        ListaGeometrias listGeo = new ListaGeometrias();
        for (int i = 0; i < objGeometrias.getChildCount(); i++) {

            DefaultMutableTreeNode listNode = (DefaultMutableTreeNode) objGeometrias.getChildAt(i);
            listGeo = (ListaGeometrias) listNode.getUserObject();
            //System.out.println("LISTA::: " + listGeo.getGeo().size());
            listVectorGeometry.add(listGeo);
        /*
        if (!listGeo.getGeo().isEmpty()) {
        
        for (int j = 0; j < listGeo.getGeo().size(); j++) {
        g1 = (Geometria) listGeo.getGeo().get(j);
        listVectorGeometry.add(listGeo);
        }
        } else {
        listVectorGeometry.add(listGeo);
        }*/
        }

        return listVectorGeometry;
    }

    /**
     * Retorna Vector com lista de FonteEletromagneticaSimulacao
     * @return Vector FonteEletromagneticaSimulacao
     */
    public Vector getListaFontes() {
        Vector listVectorFontes = new Vector();
        /* for para o objeto 'nodeTree' que contem os grupos de objetos
         * e cada grupo de objeto contem uma lista de objetos do tipo Geometry
         */

        for (int i = 0; i < objFontes.getChildCount(); i++) {

            DefaultMutableTreeNode listNode = (DefaultMutableTreeNode) objFontes.getChildAt(i);
            FonteEletromagneticaSimulacao fonte = (FonteEletromagneticaSimulacao) listNode.getUserObject();
            listVectorFontes.add(fonte);
        }

        // System.out.println("tamanho lista fontes: " + listVectorFontes.size());
        return listVectorFontes;
    }

    /**
     * Retorna Vector com lista de ListaGeometrias 
     * @return Vector ListaGeometrias
     */
    public Geometria[] getTodasGeometrias() {
        Geometria[] vetorGeometrias = null;

        /* for para o objeto 'nodeTree' que contem os grupos de objetos
         * e cada grupo de objeto contem uma lista de objetos do tipo Geometry
         */
        Geometria g1 = new Geometria();
        DefaultMutableTreeNode listNode = null;
        ListaGeometrias listGeo = null;
        int count = 0;
        for (int i = 0; i < objGeometrias.getChildCount(); i++) {

            listNode = (DefaultMutableTreeNode) objGeometrias.getChildAt(i);
            listGeo = (ListaGeometrias) listNode.getUserObject();
            /* count = numero total de geometrias */
            for (int j = 0; j < listGeo.getGeo().size(); j++) {
                count++;
            }
        }
        /* Declarando o vetor agora com o count */
        vetorGeometrias = new Geometria[count];
        count = 0;

        for (int i = 0; i < objGeometrias.getChildCount(); i++) {

            listNode = (DefaultMutableTreeNode) objGeometrias.getChildAt(i);
            listGeo = (ListaGeometrias) listNode.getUserObject();

            /* Preechendo vetorGeometrias  */
            for (int j = 0; j < listGeo.getGeo().size(); j++) {
                g1 = (Geometria) listGeo.getGeo().get(j);
                vetorGeometrias[count] = g1;
                count++;

            }
        }
        return vetorGeometrias;
    }

    /**
     * Retorna todos os relatórios gerados que estão na estrutura da árvore
     * @return Vector
     */
    public Vector getTodosRelatorios() {
        DefaultMutableTreeNode listNode;
        Visualizador v = null;
        Vector relatorios = new Vector();

        for (int i = 0; i < objRelatorios.getChildCount(); i++) {

            listNode = (DefaultMutableTreeNode) objRelatorios.getChildAt(i);
            relatorios.add((Visualizador) listNode.getUserObject());

        }
        return relatorios;

    }

    /**
     * Retorna todos os Pre Relatórios gerados que estão na estrutura da árvore
     * @return Vector
     */
    public Vector getTodosPreRelatorios() {
        DefaultMutableTreeNode no;
        JanelaInserirRelatorios v = null;
        Vector preRelatorios = new Vector();


        if (objRelatorios.isLeaf()) {
            preRelatorios.clear();
            return null;
        } else {
            preRelatorios.clear();
            for (int i = 0; i < objRelatorios.getChildCount(); i++) {

                no = (DefaultMutableTreeNode) objRelatorios.getChildAt(i);
                if (no.getUserObject() instanceof JanelaInserirRelatorios) {

                    v = ((JanelaInserirRelatorios) no.getUserObject());
                    preRelatorios.add(v.getRelatorioPosProcessamento());

                }

            }

            return preRelatorios;

        }

    }

    /**
     * Retorna todas as Geometrias da cena de simulação incluído o domínio computacional
     * @param dominio
     * @return
     */
    public Geometria[] getTodasGeometrias(Geometria dominio) {
        Geometria[] vetorGeometrias = null;

        /* for para o objeto 'nodeTree' que contem os grupos de objetos
         * e cada grupo de objeto contem uma lista de objetos do tipo Geometry
         */
        Geometria g1 = new Geometria();
        DefaultMutableTreeNode listNode = null;
        ListaGeometrias listGeo = null;
        int count = 0;
        for (int i = 0; i < objGeometrias.getChildCount(); i++) {

            listNode = (DefaultMutableTreeNode) objGeometrias.getChildAt(i);
            listGeo = (ListaGeometrias) listNode.getUserObject();
            /* count = numero total de geometrias */
            for (int j = 0; j < listGeo.getGeo().size(); j++) {
                count++;
            }
        }
        /* Declarando o vetor agora com o count */
        vetorGeometrias = new Geometria[count + 1];
        vetorGeometrias[0] = dominio;
        count = 1;

        for (int i = 0; i < objGeometrias.getChildCount(); i++) {

            listNode = (DefaultMutableTreeNode) objGeometrias.getChildAt(i);
            listGeo = (ListaGeometrias) listNode.getUserObject();

            /* Preechendo vetorGeometrias  */
            for (int j = 0; j < listGeo.getGeo().size(); j++) {
                g1 = (Geometria) listGeo.getGeo().get(j);
                vetorGeometrias[count] = g1;
                count++;

            }
        }
        return vetorGeometrias;
    }

    /**
     * Adiciona um novo objeto modelado que contem uma lista de objetos Geometry
     * @param ListaGeometrias 
     */
    public void addListaGeometria(ListaGeometrias geo) {

        /* Insere o objeto geo no nó geoList */
        DefaultMutableTreeNode geoList = new DefaultMutableTreeNode(geo);

        /* 
         * Se a lista não contiver nenhum objeto Geometry é inserido apenas
         * o objeto 'geoList' para posteriormente ela ser preenchida com outras
         * formas basicas (Geometry)
         */
        if (geo.getGeo().isEmpty()) {

            objGeometrias.add(geoList);
            tree.updateUI();

        } else {

            for (int i = 0; i <= geo.getGeo().size() - 1; i++) {
                Geometria g = (Geometria) geo.getGeo().get(i);
                /* Triangulariza Geometria quando esta é inserida na Arvore */
                g.setListaTriangulos(g.getAtributos().triangularizarGeometria());
                DefaultMutableTreeNode geoNode = new DefaultMutableTreeNode(g);
                geoList.add(geoNode);
                objGeometrias.add(geoList);
            }

        }
    }

    /**
     * Adiciona um novo objeto modelado que contem uma lista de objetos Geometry
     * @param ListaGeometrias 
     */
    public void addFonte(FonteEletromagneticaSimulacao fonte) {

        /* Insere o objeto fonte no nó geoList */
        DefaultMutableTreeNode fonteList = new DefaultMutableTreeNode(fonte);
        objFontes.add(fonteList);
        tree.updateUI();

    }

    /**
     * Adiciona um novo objeto Relatório à árvore de elementos
     * @param Visualizador - v 
     */
    public void addRelatorio(Visualizador v) {

        /* Insere o objeto fonte no nó geoList */
        boolean status = false;
        DefaultMutableTreeNode relatorio = new DefaultMutableTreeNode(v); //encapsula objeto 'v'
        // pega ultimo da lista selecionado
        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        selectedNode.add(relatorio);
        tree.updateUI();

    }

    public void removerPreRelatorios() {



        for (int i = 0; i < objRelatorios.getChildCount(); i++) {

            if (objRelatorios.getChildAt(i) instanceof JanelaInserirRelatorios) {

                objRelatorios.remove(i);

            }

        }

    }

    public void addPreRelatorio(JanelaInserirRelatorios j) {

        /* Insere o objeto fonte no nó geoList */
        DefaultMutableTreeNode janelaPre = new DefaultMutableTreeNode(j);
        objRelatorios.add(janelaPre);
        tree.updateUI();

    }

    /**
     * Recebe um Vector de relatorioPosProcessamento para ser adicionado a
     * arvore de objetos
     * @param v
     */
    public void addVectorPreRelatorio(Vector v, String caminho) {

        RelatorioPosProcessamento r;
        for (int i = 0; i < v.size(); i++) {

            r = (RelatorioPosProcessamento) v.get(i);

            /* Primeiro cria a JanelaInserirRelatorios */
            JanelaInserirRelatorios j = new JanelaInserirRelatorios(new javax.swing.JFrame(), true, caminho);
            j.setRelatorioPosProcessamento(r);
            j.mudarPropriedadesJanela();
            /* Depois adicona-se como uma janela normal na arvore */
            addPreRelatorio(j);


        }

    }

    /**
     * Insere um Objeto da classe Geometry na lista de Geometrias (ListaGeometrias)
     * que o usuário previamente selecionou, caso este nao selecione o m�todo ignora a inser��o
     * @param geometry 
     */
    public void addGeometria(Geometria geometry) {

        /* pega ultima selecao na arvore feita pelo usuario */
        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

        /* adiciona somente se o "nó" selecionado for um Objeto ListaGeometrias
         * que se refere ao grupo de geometrias
         */
        try {
            if (selectedNode.getLevel() == 2) {

                /* Cast para pegar objeto ListaGeometrias */
                ListaGeometrias listG = (ListaGeometrias) selectedNode.getUserObject();
                /* Adicionando nova geometria no objeto ListaGeometrias */
                listG.addGeometry(geometry);
                /* Adicionando nova geometria na Estrutura da Arvore */
                DefaultMutableTreeNode geoNode = new DefaultMutableTreeNode(geometry);
                selectedNode.add(geoNode);
                tree.updateUI();
            }

        } catch (Exception e) {
            System.out.println("selecione grupo de geometrias");
        }

    }

    /**
     * Atualiza objeto (ListaGeometrias) modificado pelo usu�rio, neste caso o ID
     * nó alterado, pois ele tem uma numeração própria
     * @param ListaGeometrias 
     */
    public void atualizaListaGeometrias(ListaGeometrias l) {

        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        selectedNode.setUserObject(l);
        tree.updateUI();

    }

    /**
     * Atualiza objeto (ListaGeometrias) modificado pelo usu�rio, neste caso o ID
     * nó alterado, pois ele tem uma numeração própria
     * @param ListaGeometrias 
     */
    public void atualizarGeometria(Geometria g) {

        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        selectedNode.setUserObject(g);
        tree.updateUI();

    }

    /**
     * Remove objeto previamente selecionado pelo usuário, seja este uma 
     * instância de Geometria ou de ListaGeometrias
     * Caso o usuário não faça a seleção, nada é feito.
     */
    public boolean remObjSelecionado() {

        boolean status = false;
        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

        Object objSelecionado = selectedNode.getUserObject();
        /* remove objeto da arvore somente se nao for nulo, se tiver pai e se nao for nivel 1
         * nivel 1 é o nivel "Geometrias" e "Relatorios" 
         */
        // if (selectedNode != null && selectedNode.getParent() != null && selectedNode.getLevel() != 1) {

        if (objSelecionado instanceof FonteEletromagneticaSimulacao) {
            FonteEletromagneticaSimulacao f =
                    (FonteEletromagneticaSimulacao) objSelecionado;
            model.removeNodeFromParent(selectedNode);
            tree.updateUI();
            status = true;

        }

        /* Removendo Objeto caso este seja uma Relatório */
        if (objSelecionado instanceof Visualizador) {

            model.removeNodeFromParent(selectedNode);
            tree.updateUI();
            status = true;

        }

        /* Removendo Objeto caso este seja uma PreRelatório */
        if (objSelecionado instanceof JanelaInserirRelatorios) {

            objRelatorios.remove(selectedNode);
            tree.updateUI();
            status = true;

        }

        /* Removendo Objeto caso este seja uma Geometria */
        if (selectedNode.getUserObject() instanceof Geometria) {

            Geometria g = (Geometria) selectedNode.getUserObject();
            /* Pega o pai da Geometria selecionada */
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedNode.getParent();
            /* Pega o conteudo (ListGeometri) do pai da Geometria */
            ListaGeometrias listG = (ListaGeometrias) node.getUserObject();

            Vector l = (Vector) listG.getGeo();
            int index = l.indexOf(g);
            //listG.setGeo(l);
            l.remove(index);
            model.removeNodeFromParent(selectedNode);
            tree.updateUI();
            status = true;

        /* Removendo Objeto caso este seja uma ListaGeometrias */
        }
        if (selectedNode.getUserObject() instanceof ListaGeometrias) {

            objGeometrias.remove(selectedNode);
            tree.updateUI();
            status = true;

        }

        // }
        return status;

    }

    /**
     * Atualiza toda estrutura da árvore
     */
    public void updateTree() {
        tree.updateUI();
    }

    /**
     * @return Quantidade de Geometrias
     */
    public int getQuantidadeGeometrias() {
        int contador = 0;
        /* for para o objeto 'nodeTree' que contem os grupos de objetos
         * e cada grupo de objeto contem uma lista de objetos do tipo Geometry
         */
        Geometria g1 = new Geometria();
        for (int i = 0; i < objGeometrias.getChildCount(); i++) {

            DefaultMutableTreeNode listNode = (DefaultMutableTreeNode) objGeometrias.getChildAt(i);
            ListaGeometrias listGeo = (ListaGeometrias) listNode.getUserObject();

            if (!listGeo.getGeo().isEmpty()) {

                for (int j = 0; j < listGeo.getGeo().size(); j++) {
                    contador++;
                }
            } else {
                contador = 0;
            }
        }
        return contador;
    }
}
